#!/usr/bin/python

"""
The HiPerCopS Architecture Simulator.
"""

import getopt
import sys
import re

import system
import device
from utils import *

def main(argv):
    
    system_file = ''
    input_file = ''
    output_file = ''
    map_alg = 'default'
    num_faults = 0
    fault_map = ''
    
    short_opts = "hvp:s:i:o:m:f:F:"
    long_opts = ["help", "version", "project=", "system=", 
                 "input=", "output=", "mapping=", "faults=",
                 "faultmap="]

    #process the commandline arguments
    try:
        opts, args = getopt.getopt(argv, short_opts, long_opts)
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err)
        usage()
        sys.exit(2)
    output = None
    verbose = False
    for opt, arg in opts:
        if opt in ("-h", "--help"):
            version()
            usage()
            sys.exit()
        elif opt in ("-v", "--version"):
            version()
            sys.exit()
        elif opt in ("-p", "--project"):
            project_files = read_proj(arg)
        elif opt in ("-s", "--system"):
            system_file = arg
        elif opt in ("-i", "--input"):
            input_file = arg
        elif opt in ("-o", "--output"):
            output_file = arg
        elif opt in ("-m", "--mapping"):
            map_alg = arg
        elif opt in ("-f", "--faults"):
            num_faults = int(arg)
        elif opt in ("-F", "--faultmap"):
            fault_map = arg
        else:
            assert False, "unhandled option"
            
    #make sure the required arguments were there
    if len(system_file) == 0 or len(input_file) == 0 or len(output_file) == 0:
        print "Error: missing required arguments"
        usage()
        exit(2)
    
    #allow system, input, and output options to override project option
    if system_file == '':
        system_file = project_files['system']
    if input_file == '':
        input_file = project_files['input']
    if output_file == '':
        output_file = project_files['output']
        
    #load the libraries
    load_libs()

    #execute the program
    d = device.Device()
    d.add_faults(fault_map, num_faults)
    d.add_system(system_file)
    d.map(map_alg)
    d.run(input_file, output_file)

def version():
    """
    print version information to stdout
    """
    print "spoc - A Medium-Grain Reconfigurable Hardware Simulation Tool"
    print "Version: 0.2 'rex'"
    print "Author: Kylan Robinson"
    print "License: GPL V3"

def usage():
    """
    print usage information to stdout
    """
    print "\nUsage:\tspoc [options]\n"
    print "Options:\n"
    print "\t-h, --help\t\t\tdisplay usage"
    print "\t-v, --version\t\t\tdisplay version"
    print "\t-p[file], --project[file]\tuse file as the project specification"
    print "\t-s[file], --system[file]\tuse file as the system specification"
    print "\t-i[file], --input[file]\t\tuse file as list of inputs"
    print "\t-o[file], --output[file]\twrite the results to file"
    print "\t-m[alg], --mapping[alg]\t\tuse algorithm alg to map structures to the device"
    print "\t-f#, --faults#\t\t\trandomly place # faults on the device"
    print "\n"
    print "[alg]\tPossible values:"
    print "\t\t`naive`: no fault avoidance"
    print "\t\t`simple`: basic fault avoidance"
    print "\t\t`sizeaware`: fault avoidance, larger structures mapped first"
    print "\t\t`sizeaware-rotate`: sizeaware approach, plus rotate structures that don't fit"

def read_proj(filename):
    """
    read a project file and return a dictionary of file names in the project
    """
    pattern = re.compile("(.*),(.*),(.*)")
    
    #open and read the file, it should just be a single line of text
    file = open(filename)
    raw_text = file.read().strip()
    
    proj_files = pattern.search(raw_text).groups()
    
    #return the dictionary
    return {'system':proj_files[0], 'input':proj_files[1], 'output':proj_files[2]}
    
if __name__ == "__main__":
    main(sys.argv[1:])
